<template>
  <div class="crud-image-uploader" :class="{ 'is-disabled': disabled, 'is-readonly': readonly }">
    <!-- 上传区域 -->
    <div class="upload-container" :style="containerStyle">
      <el-upload ref="uploadRef" class="image-uploader" v-bind="$attrs" :auto-upload="mode === 'immediate'"
        :show-file-list="false" :accept="acceptTypes" :limit="1" :on-change="handleFileChange"
        :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess" :on-error="handleUploadError"
        :on-progress="handleUploadProgress" :disabled="disabled || readonly || uploadLoading"
        :action="uploadConfig?.action || '#'" :headers="uploadConfig?.headers" :data="uploadConfig?.data"
        :name="uploadConfig?.name || 'file'" :with-credentials="uploadConfig?.withCredentials"
        :timeout="uploadConfig?.timeout" :http-request="customUpload ? handleCustomUpload : undefined">
        <!-- 上传中状态 -->
        <div v-if="uploadLoading" class="upload-loading" :style="previewStyle">
          <el-icon class="is-loading loading-icon">
            <Loading />
          </el-icon>
          <div class="loading-content">
            <p class="loading-text">正在上传...</p>
            <div v-if="currentProgress" class="progress-info">
              <el-progress :percentage="currentProgress.percent" :stroke-width="4" :show-text="false"
                class="upload-progress" />
              <span class="progress-text">{{ currentProgress.percent }}%</span>
            </div>
          </div>
        </div>

        <!-- 已有图片预览 -->
        <div v-else-if="currentImageUrl" class="image-preview" :style="previewStyle">
          <img :src="currentImageUrl" class="preview-image" alt="预览图片" />

          <!-- 遮罩层 -->
          <div v-if="!readonly" class="image-overlay">
            <div class="overlay-actions">
              <el-icon class="action-icon preview-icon" @click.stop="handlePreview">
                <ZoomIn />
              </el-icon>
              <el-icon class="action-icon replace-icon" @click.stop="handleReplace">
                <RefreshRight />
              </el-icon>
              <el-icon v-if="showDelete" class="action-icon delete-icon" @click.stop="handleDelete">
                <Delete />
              </el-icon>
            </div>
          </div>

          <!-- 错误状态重试按钮 -->
          <div v-if="fileInfo?.status === 'error' && showRetry" class="error-retry">
            <el-button type="danger" size="small" @click.stop="handleRetry">
              <el-icon>
                <RefreshRight />
              </el-icon>
              重试
            </el-button>
          </div>
        </div>

        <!-- 上传占位符 -->
        <div v-else class="upload-placeholder" :style="previewStyle">
          <el-icon class="upload-icon">
            <Plus />
          </el-icon>
          <div class="upload-content">
            <p class="upload-text">{{ placeholder || '点击上传图片' }}</p>
            <p v-if="tip" class="upload-tip">{{ tip }}</p>
            <p v-else class="upload-tip">{{ defaultTip }}</p>
          </div>
        </div>
      </el-upload>
    </div>

    <!-- 图片预览对话框 -->
    <el-dialog v-model="previewDialogVisible" title="图片预览" width="80%" center>
      <div class="preview-dialog-content">
        <img :src="currentImageUrl" alt="图片预览" class="preview-dialog-image" />
      </div>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, nextTick } from 'vue'
import { ElMessage, ElMessageBox, type UploadFile, type UploadRawFile, type UploadProgressEvent } from 'element-plus'
import { Plus, Loading, ZoomIn, RefreshRight, Delete } from '@element-plus/icons-vue'
import type {
  CrudImageUploaderProps,
  CrudImageUploaderEmits,
  FileInfo,
  UploadProgress,
  UploadResult
} from './types'

/**
 * 组件属性定义
 */
const props = withDefaults(defineProps<CrudImageUploaderProps>(), {
  mode: 'delayed',
  disabled: false,
  readonly: false,
  placeholder: '点击上传图片',
  showDelete: true,
  showRetry: true,
  previewConfig: () => ({
    width: 120,
    height: 120,
    round: false,
    border: true,
    borderColor: '#d9d9d9',
    backgroundColor: '#fafafa'
  }),
  validationConfig: () => ({
    allowedTypes: ['image/png', 'image/jpeg', 'image/jpg'],
    maxSize: 2
  }),
  uploadConfig: () => ({
    name: 'file',
    withCredentials: false,
    timeout: 30000
  })
})

/**
 * 组件事件定义
 */
const emit = defineEmits<CrudImageUploaderEmits>()

// 响应式数据
const uploadRef = ref()
const uploadLoading = ref(false)
const previewDialogVisible = ref(false)
const currentProgress = ref<UploadProgress | null>(null)
const fileInfo = ref<FileInfo | null>(null)
const pendingFile = ref<File | null>(null)

// 当前图片URL
const currentImageUrl = computed(() => {
  return fileInfo.value?.serverUrl || fileInfo.value?.previewUrl || props.modelValue || ''
})

// 接受的文件类型
const acceptTypes = computed(() => {
  return props.validationConfig?.allowedTypes?.join(',') || 'image/*'
})

// 默认提示文本
const defaultTip = computed(() => {
  const config = props.validationConfig
  if (!config) return '支持图片格式，大小不超过2MB'

  const types = config.allowedTypes?.map(type => type.split('/')[1]?.toUpperCase() || '').join('、') || '图片'
  const maxSize = config.maxSize || 2
  return `支持${types}格式，大小不超过${maxSize}MB`
})

// 容器样式
const containerStyle = computed(() => {
  const config = props.previewConfig
  if (!config) return {}

  return {
    width: typeof config.width === 'number' ? `${config.width}px` : config.width,
    height: typeof config.height === 'number' ? `${config.height}px` : config.height
  }
})

// 预览样式
const previewStyle = computed(() => {
  const config = props.previewConfig
  if (!config) return {}

  return {
    width: '100%',
    height: '100%',
    borderRadius: config.round ? '50%' : '8px',
    border: config.border ? `2px solid ${config.borderColor}` : 'none',
    backgroundColor: config.backgroundColor
  }
})

/**
 * 监听modelValue变化
 */
watch(
  () => props.modelValue,
  (newValue) => {
    if (newValue && (!fileInfo.value || fileInfo.value.serverUrl !== newValue)) {
      // 如果有新的URL且与当前不同，更新fileInfo
      if (newValue !== fileInfo.value?.previewUrl) {
        fileInfo.value = null
        pendingFile.value = null
      }
    } else if (!newValue) {
      // 如果URL被清空，重置状态
      fileInfo.value = null
      pendingFile.value = null
    }
  },
  { immediate: true }
)

/**
 * 文件验证函数
 * @param file - 要验证的文件
 * @returns 验证结果和错误信息
 */
const validateFile = (file: File): { valid: boolean; error?: string } => {
  const config = props.validationConfig

  // 检查文件类型
  const isValidType = config?.allowedTypes?.includes(file.type) ?? true
  if (config?.allowedTypes && !isValidType) {
    const allowedTypesText = config.allowedTypes?.map(type => type.split('/')[1]?.toUpperCase() || '').join('、') || ''
    return { valid: false, error: `文件格式不支持，请选择${allowedTypesText}格式的图片` }
  }

  // 检查文件大小
  const fileSizeMB = file.size / 1024 / 1024
  if (config?.maxSize && fileSizeMB > config.maxSize) {
    return { valid: false, error: `文件大小不能超过${config.maxSize}MB` }
  }

  if (config?.minSize && fileSizeMB < config.minSize) {
    return { valid: false, error: `文件大小不能小于${config.minSize}MB` }
  }

  return { valid: true }
}

/**
 * 创建文件预览URL
 * @param file - 文件对象
 * @returns Promise<string> - 预览URL
 */
const createPreviewUrl = (file: File): Promise<string> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = (e) => {
      if (e.target?.result) {
        resolve(e.target.result as string)
      } else {
        reject(new Error('无法读取文件'))
      }
    }
    reader.onerror = () => reject(new Error('文件读取失败'))
    reader.readAsDataURL(file)
  })
}

/**
 * 处理文件选择变化
 * @param uploadFile - 上传文件信息
 */
const handleFileChange = async (uploadFile: UploadFile): Promise<void> => {
  if (!uploadFile.raw) return

  // 验证文件
  const validation = validateFile(uploadFile.raw)
  if (!validation.valid) {
    ElMessage.error(validation.error!)
    emit('validation-error', validation.error!, uploadFile.raw)
    return
  }

  try {
    // 创建预览URL
    const previewUrl = await createPreviewUrl(uploadFile.raw)

    // 创建文件信息
    const newFileInfo: FileInfo = {
      file: uploadFile.raw,
      name: uploadFile.name,
      size: uploadFile.size!,
      type: uploadFile.raw.type,
      previewUrl,
      status: 'pending'
    }

    fileInfo.value = newFileInfo
    pendingFile.value = uploadFile.raw

    // 触发文件选择事件
    emit('file-select', newFileInfo)

    // 如果是立即上传模式，开始上传
    if (props.mode === 'immediate') {
      await startUpload()
    } else {
      // 延迟上传模式，更新modelValue为预览URL
      emit('update:modelValue', previewUrl)
    }

    ElMessage.success('文件选择成功')
  } catch (error) {
    console.error('文件处理失败:', error)
    ElMessage.error('文件处理失败，请重试')
  }
}

/**
 * 上传前的处理
 * @param rawFile - 原始文件
 * @returns boolean - 是否继续上传
 */
const handleBeforeUpload = (rawFile: UploadRawFile): boolean => {
  const validation = validateFile(rawFile)
  if (!validation.valid) {
    ElMessage.error(validation.error!)
    emit('validation-error', validation.error!, rawFile)
    return false
  }
  return true
}

/**
 * 自定义上传处理
 */
const handleCustomUpload = async (): Promise<void> => {
  if (!props.customUpload || !fileInfo.value) return

  try {
    uploadLoading.value = true
    fileInfo.value.status = 'uploading'
    emit('upload-start', fileInfo.value)

    const result = await props.customUpload(fileInfo.value.file)

    if (result.success && result.url) {
      fileInfo.value.serverUrl = result.url
      fileInfo.value.status = 'success'
      emit('update:modelValue', result.url)
      emit('upload-success', result, fileInfo.value)
      ElMessage.success('上传成功')
    } else {
      throw new Error(result.error || '上传失败')
    }
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : '上传失败'
    fileInfo.value.status = 'error'
    fileInfo.value.error = errorMessage
    emit('upload-error', errorMessage, fileInfo.value)
    ElMessage.error(errorMessage)
  } finally {
    uploadLoading.value = false
    currentProgress.value = null
  }
}

/**
 * 上传成功处理
 * @param response - 服务器响应
 */
const handleUploadSuccess = (response: Record<string, unknown>): void => {
  if (!fileInfo.value) return

  try {
    // 假设服务器返回格式为 { success: true, data: { url: 'xxx' } }
    const responseData = response as { data?: { url?: string }; url?: string }
    const url = responseData.data?.url || responseData.url
    if (url) {
      fileInfo.value.serverUrl = url
      fileInfo.value.status = 'success'
      emit('update:modelValue', url)

      const result: UploadResult = {
        success: true,
        url,
        response
      }
      emit('upload-success', result, fileInfo.value)
      ElMessage.success('上传成功')
    } else {
      throw new Error('服务器未返回有效的图片URL')
    }
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : '上传失败'
    handleUploadError(new Error(errorMessage))
  } finally {
    uploadLoading.value = false
    currentProgress.value = null
  }
}

/**
 * 上传失败处理
 * @param error - 错误信息
 */
const handleUploadError = (error: Error): void => {
  if (!fileInfo.value) return

  const errorMessage = error.message || '上传失败'
  fileInfo.value.status = 'error'
  fileInfo.value.error = errorMessage

  emit('upload-error', errorMessage, fileInfo.value)
  ElMessage.error(errorMessage)

  uploadLoading.value = false
  currentProgress.value = null
}

/**
 * 上传进度处理
 * @param event - 进度事件
 */
const handleUploadProgress = (event: UploadProgressEvent): void => {
  if (!fileInfo.value) return

  const progress: UploadProgress = {
    percent: Math.round(event.percent || 0),
    loaded: event.loaded || 0,
    total: event.total || 0
  }

  currentProgress.value = progress
  fileInfo.value.progress = progress
  fileInfo.value.status = 'uploading'

  emit('upload-progress', progress, fileInfo.value)
}

/**
 * 开始上传（用于延迟上传模式）
 */
const startUpload = async (): Promise<void> => {
  if (!fileInfo.value || !pendingFile.value) {
    throw new Error('没有待上传的文件')
  }

  if (props.customUpload) {
    await handleCustomUpload()
  } else {
    // 使用Element Plus的上传组件
    uploadLoading.value = true
    fileInfo.value.status = 'uploading'
    emit('upload-start', fileInfo.value)

    // 触发Element Plus上传
    await nextTick()
    uploadRef.value?.submit()
  }
}

/**
 * 获取待上传的文件（供外部调用）
 */
const getPendingFile = (): File | null => {
  return pendingFile.value
}

/**
 * 手动上传（供外部调用）
 */
const upload = async (): Promise<string> => {
  if (fileInfo.value?.serverUrl) {
    return fileInfo.value.serverUrl
  }

  if (!pendingFile.value) {
    throw new Error('没有待上传的文件')
  }

  await startUpload()

  if (!fileInfo.value?.serverUrl) {
    throw new Error('上传失败')
  }

  return fileInfo.value.serverUrl
}

/**
 * 处理图片预览
 */
const handlePreview = (): void => {
  if (currentImageUrl.value) {
    previewDialogVisible.value = true
  }
}

/**
 * 处理图片替换
 */
const handleReplace = (): void => {
  if (props.disabled || props.readonly) return

  // 触发文件选择
  const input = uploadRef.value?.$el?.querySelector('input[type="file"]')
  if (input) {
    input.click()
  }
}

/**
 * 处理图片删除
 */
const handleDelete = async (): Promise<void> => {
  if (props.disabled || props.readonly) return

  try {
    await ElMessageBox.confirm('确定要删除这张图片吗？', '确认删除', {
      type: 'warning',
      confirmButtonText: '确定',
      cancelButtonText: '取消'
    })

    const currentFileInfo = fileInfo.value

    // 重置状态
    fileInfo.value = null
    pendingFile.value = null
    currentProgress.value = null
    uploadLoading.value = false

    // 更新modelValue
    emit('update:modelValue', '')

    // 触发删除事件
    if (currentFileInfo) {
      emit('file-delete', currentFileInfo)
    }

    ElMessage.success('图片已删除')
  } catch {
    // 用户取消删除
  }
}

/**
 * 处理重试上传
 */
const handleRetry = async (): Promise<void> => {
  if (!fileInfo.value || !pendingFile.value) return

  try {
    fileInfo.value.status = 'pending'
    fileInfo.value.error = undefined
    currentProgress.value = null

    await startUpload()
  } catch (error) {
    console.error('重试上传失败:', error)
  }
}

/**
 * 重置组件状态
 */
const reset = (): void => {
  console.log('🔄 [CrudImageUploader] reset 方法被调用')
  console.log('🔄 [CrudImageUploader] 重置前的状态:', {
    fileInfo: fileInfo.value,
    pendingFile: pendingFile.value,
    currentImageUrl: currentImageUrl.value,
    modelValue: props.modelValue
  })

  fileInfo.value = null
  pendingFile.value = null
  currentProgress.value = null
  uploadLoading.value = false
  previewDialogVisible.value = false
  emit('update:modelValue', '')

  console.log('🔄 [CrudImageUploader] reset 方法执行完成')
}

// 暴露给父组件的方法
defineExpose({
  upload,
  reset,
  getPendingFile,
  startUpload
})
</script>

<style lang="scss" scoped>
.crud-image-uploader {
  display: inline-block;

  &.is-disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }

  &.is-readonly {
    .image-overlay {
      display: none;
    }
  }

  .upload-container {
    position: relative;
    display: inline-block;
  }

  .image-uploader {
    :deep(.el-upload) {
      border: 2px dashed #d9d9d9;
      border-radius: 8px;
      cursor: pointer;
      position: relative;
      overflow: hidden;
      transition: all 0.3s ease;
      display: flex;
      align-items: center;
      justify-content: center;

      &:hover {
        border-color: #409eff;
        background-color: #f5f7fa;
      }

      &.is-disabled {
        cursor: not-allowed;
        border-color: #e4e7ed;
        background-color: #f5f7fa;
      }
    }
  }

  .upload-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: #409eff;
    background-color: rgba(255, 255, 255, 0.9);

    .loading-icon {
      font-size: 24px;
      margin-bottom: 8px;
    }

    .loading-content {
      text-align: center;

      .loading-text {
        font-size: 12px;
        margin: 0 0 8px 0;
      }

      .progress-info {
        width: 80px;

        .upload-progress {
          margin-bottom: 4px;
        }

        .progress-text {
          font-size: 10px;
          color: #666;
        }
      }
    }
  }

  .image-preview {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;

    .preview-image {
      width: 100%;
      height: 100%;
      object-fit: cover;
      display: block;
    }

    .image-overlay {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: rgba(0, 0, 0, 0.5);
      display: flex;
      align-items: center;
      justify-content: center;
      opacity: 0;
      transition: opacity 0.3s ease;

      .overlay-actions {
        display: flex;
        gap: 8px;

        .action-icon {
          width: 24px;
          height: 24px;
          color: white;
          cursor: pointer;
          transition: transform 0.2s ease;

          &:hover {
            transform: scale(1.2);
          }

          &.preview-icon:hover {
            color: #409eff;
          }

          &.replace-icon:hover {
            color: #e6a23c;
          }

          &.delete-icon:hover {
            color: #f56c6c;
          }
        }
      }
    }

    &:hover .image-overlay {
      opacity: 1;
    }

    .error-retry {
      position: absolute;
      bottom: 4px;
      right: 4px;
    }
  }

  .upload-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: #8c939d;

    .upload-icon {
      font-size: 28px;
      margin-bottom: 8px;
    }

    .upload-content {
      text-align: center;

      .upload-text {
        font-size: 14px;
        margin: 0 0 4px 0;
        color: #606266;
      }

      .upload-tip {
        font-size: 12px;
        margin: 0;
        color: #909399;
        line-height: 1.2;
      }
    }
  }

  .preview-dialog-content {
    text-align: center;

    .preview-dialog-image {
      max-width: 100%;
      max-height: 70vh;
      object-fit: contain;
    }
  }
}

// 响应式设计
@media (max-width: 768px) {
  .crud-image-uploader {
    .image-overlay {
      opacity: 1;
      background-color: rgba(0, 0, 0, 0.3);

      .overlay-actions {
        .action-icon {
          width: 20px;
          height: 20px;
        }
      }
    }
  }
}

// 深色模式
@media (prefers-color-scheme: dark) {
  .crud-image-uploader {
    .image-uploader {
      :deep(.el-upload) {
        border-color: $border-color-light-dark;

        &:hover {
          background-color: #0f172a;
          border-color: var(--primary-color, $primary-color);
        }

        &.is-disabled {
          border-color: #374151;
          background-color: #111827;
        }
      }
    }

    .upload-loading {
      color: var(--primary-color, $primary-color);
      background-color: rgba(0, 0, 0, 0.4);

      .progress-info .progress-text {
        color: $text-color-secondary-dark;
      }
    }

    .image-preview {
      .image-overlay {
        background-color: rgba(0, 0, 0, 0.6);
      }
    }

    .upload-placeholder {
      color: $text-color-secondary-dark;

      .upload-content {
        .upload-text {
          color: $text-color-primary-dark;
        }

        .upload-tip {
          color: $text-color-secondary-dark;
        }
      }
    }
  }
}
</style>
